package com.atlzk.seckill.seckill.service.impl;

import com.atlzk.group.tgou.entity.CodeMsg;
import com.atlzk.group.tgou.entity.ResultMsg;
import com.atlzk.seckill.seckill.dao.PorderDao;
import com.atlzk.seckill.seckill.dao.SeckillDao;
import com.atlzk.seckill.seckill.entity.PorderEntity;
import com.atlzk.seckill.seckill.entity.SeckillEntity;
import com.atlzk.seckill.seckill.entity.SeckillMessage;
import com.atlzk.seckill.seckill.service.PorderService;
import com.atlzk.seckill.seckill.utils.MQConfig;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atlzk.common.utils.PageUtils;
import com.atlzk.common.utils.Query;

import com.atlzk.seckill.seckill.dao.SorderDao;
import com.atlzk.seckill.seckill.entity.SorderEntity;
import com.atlzk.seckill.seckill.service.SorderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;


@Service("sorderService")
public class SorderServiceImpl extends ServiceImpl<SorderDao, SorderEntity> implements SorderService {

    @Autowired
    private SeckillDao seckillDao;

    @Autowired
    private PorderDao porderDao;

    @Autowired
    private PorderService porderService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SorderEntity> page = this.page(
                new Query<SorderEntity>().getPage(params),
                new QueryWrapper<SorderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    @Transactional
    public ResultMsg seckill(Long userId, Long seckillId) {
        String seckill_scount= stringRedisTemplate.opsForValue().get("seckill_count" + seckillId);
        //1.有无对应商品
        if (StringUtils.isEmpty(seckill_scount)){
            return ResultMsg.erro(CodeMsg.SECKILL_RESIS_EMPTY);
        }
        //3.redis  预减商品 库存 库存是否小于0，返回错误信息，如果不小于就继续后续操作
        Long cacheStock = stringRedisTemplate.opsForValue().decrement("seckill_count" + seckillId);
        if (cacheStock < 0) {
//            Long increment = stringRedisTemplate.opsForValue().increment("seckill_" + seckillId);//恢复库存
            //如果库存变为负数  恢复为0  否则 redis  会变为负数
            stringRedisTemplate.opsForValue().increment("seckill_count" + seckillId);
            return ResultMsg.erro(CodeMsg.Seckill_REPERTORY_DEFICIENCY);
        }
        //4.判断是否参与过秒杀（根据 userID seckillID 执行redis 查询）
        SorderEntity sorder = querySorderByUserIdAndSeckillId(userId, seckillId);
        if (sorder != null) {
            //自增  恢复他  占用的库存  redis
            stringRedisTemplate.opsForValue().increment("seckill_count" + seckillId);
            return ResultMsg.erro(CodeMsg.SECKILL_ALREADY_JOIN);
        }

        //5.准备一个实体，封装 userID and seckillID
        SeckillMessage seckillMessage = new SeckillMessage(userId, seckillId);
        //6.准备入队 使用 dricet  队列方式
        rabbitTemplate.convertAndSend(MQConfig.SECKILL_QUEUE,seckillMessage);

        return ResultMsg.success(CodeMsg.SECKILL_JOIN_RABBIRMQ);
    }

    //秒杀执行逻辑
    @Transactional
    public ResultMsg seckill_logic(Long userId, Long seckillId){
        //查找对应商品信息
//        SeckillEntity seckillEntity = seckillDao.selectById(seckillId);
        SeckillEntity seckillEntity = (SeckillEntity) redisTemplate.opsForValue().get("seckill_" + seckillId);
        //3.减少库存 生成订单详情 生成秒杀订单
        int i = seckillDao.subtractStockCount(seckillId);
        if (i > 0) {
            //生成详情
            PorderEntity porderEntity = new PorderEntity(null, userId, seckillEntity.getProductId(), seckillEntity.getProductName(), 1, seckillEntity.getSeckillPrice(), seckillEntity.getSeckillPrice(), 0, new Date(), null);
            //添加普通订单表
            porderDao.insert(porderEntity);
            SorderEntity sorderEntity = new SorderEntity(null, userId, porderEntity.getId(), seckillId);
            //1. 10条同一个人的请求 第一条成功  后9条 因为 唯一索引 报错
            //2.导致消费者消费失败  会不断监听 ——》消费失败-》死循环
            // 解决办法：使用 try cach 放走 唯一索引 报的异常
            //3.放走异常  无法触发回滚  导致9条错误请求对 库存 and  普通订单表  的操作 仍然存在
            //解决办法：在catch中手动回滚
            try {
                //根据普通订单表  生成  秒杀订单表
                baseMapper.insert(sorderEntity);
            } catch (Exception e) {
                //手动回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                log.error("一个用户重复秒杀，被唯一索引打会");
            }
            //把当前订单存入redis  目的是防止重复秒杀
            redisTemplate.opsForValue().set(userId + "_seckill_sorder_" + seckillId, sorderEntity);
            return ResultMsg.success(CodeMsg.SECKILL_ORDER_SUCCESS);
        }else {
            return ResultMsg.erro(CodeMsg.SECKILL_SUBTRACT_REPERTORY);
        }
    }

    //验证是否参与过秒杀   redis 与 数据库  双层判断
    @Transactional
    public SorderEntity querySorderByUserIdAndSeckillId(Long userId,Long seckillId){
        SorderEntity sorderEntity =null;
        sorderEntity = (SorderEntity) redisTemplate.opsForValue().get(userId + "_seckill_sorder_" + seckillId);
        if (sorderEntity == null) {
            //去数据库查询
            sorderEntity = baseMapper.selectOne(new QueryWrapper <SorderEntity>().eq("user_id", userId).eq("seckill_id", seckillId));
        }
        //有直接返回
        return sorderEntity;
    }
    /*@Override
    @Transactional
    public ResultMsg seckill(Long userId, Long seckillId) {
        //1.检查库存
        SeckillEntity seckillEntity = seckillDao.selectById(seckillId);
        if (seckillEntity.getStockCount() <= 0) {
            return ResultMsg.erro(CodeMsg.Seckill_REPERTORY_DEFICIENCY);
        }
        //2.检查是否秒杀过
//        List <SorderEntity> porderEntities = baseMapper.selectList(new QueryWrapper <SorderEntity>().eq("user_id", userId).eq("seckill_id", seckillId));
//        if (porderEntities.size() > 0) {
//            return ResultMsg.erro(CodeMsg.SECKILL_ALREADY_JOIN);
//        }else {
            //3.减少库存 生成订单详情 生成秒杀订单
        int i = seckillDao.subtractStockCount(seckillId);
        if (i>0){
            //生成详情
            PorderEntity porderEntity = new PorderEntity(null, userId, seckillEntity.getProductId(), seckillEntity.getProductName(), 1, seckillEntity.getSeckillPrice(), seckillEntity.getSeckillPrice(), 0, new Date(), null);
            porderDao.insert(porderEntity);
            SorderEntity sorderEntity = new SorderEntity(null, userId, porderEntity.getId(), seckillId);
            baseMapper.insert(sorderEntity);
            return ResultMsg.success(CodeMsg.SECKILL_ORDER_SUCCESS);
        }else {
            return ResultMsg.erro(CodeMsg.Seckill_subtract_REPERTORY);
        }

//        }

    }*/

}